using System;
using System.Collections.Generic;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
using Oops.Xna.Framework.Graphics;

namespace Oops.Xna.Framework.UI
{
	[Flags()]
	public enum AnchorStyle
	{
		None = 0,
		Top = 1,
		Bottom = 2,
		Left = 4,
		Right = 8
	}

	public enum DockStyle
	{
		None,
		Top,
		Bottom,
		Left,
		Right,
		Fill
	}

	public enum ImageLayout
	{
		None,
		Tile,
		Center,
		Stretch,
		Zoom
	}

	public enum ContentAlignment
	{
		TopLeft,
		TopCenter,
		TopRight,
		MiddleLeft,
		MiddleCenter,
		MiddleRight,
		BottomLeft,
		BottomCenter,
		BottomRight
	}

	public class Control : DrawableGameComponent
	{
		private Control parent;

		private IInternalUIService uiService;

		private string name;
		private object tag;

		private string text;
		private ContentAlignment textAlign = ContentAlignment.MiddleCenter;

		private string fontAsset = @".\Content\Fonts\control";
		private Color fontColor = Color.White;

		private string backgroundImageAsset;
		private Color backColor = Color.TransparentBlack;
		private ImageLayout backgroundImageLayout;
		private ContentAlignment backgroundImageAlign;

		private string skinAsset = @".\Content\Textures\skin";
		private Rectangle skinRectangle = new Rectangle(0, 0, 256, 256);
		private Padding skinMargin = new Padding(8);
		private ImageLayout clientAreaSkinLayout = ImageLayout.None;
		private ImageLayout nonClientAreaSkinLayout = ImageLayout.Stretch;
		
		private ControlCollection controls;

		private Point location;
		private Size size;

		private Size minimumSize;
		private Size maximumSize;

		private bool tabStop;
		private int tabIndex;

		private AnchorStyle anchor = AnchorStyle.Top & AnchorStyle.Left;
		private DockStyle dock;

		private Padding padding;
		
		private bool invalidate = true;
		private RenderTarget2D renderTarget;
		private Texture2D texture;

		public Control(Game game, string name) : base(game)
		{
			// The name parameter must be specified.
			if (string.IsNullOrEmpty(name))
			{
				throw new ArgumentNullException("name");
			}

			// Hold onto parameters.
			this.name = name;
			
			// Create the control collection.
			this.controls = new ControlCollection(this);
		}

		public Control Parent
		{
			get { return this.parent; }
			internal set 
			{
				if (this.parent != value)
				{
					this.parent = value;
					this.OnParentSized(ref this.size);
				}
			}
		}

		public string Name
		{
			get { return this.name; }
		}

		public object Tag
		{
			get { return this.tag; }
			set { this.tag = value; }
		}

		public ControlCollection Controls
		{
			get { return this.controls; }
		}

		public Point Location
		{
			get { return this.location; }
			set { this.location = value; }
		}

		public int Left
		{
			get { return this.location.X; }
		}

		public int Right
		{
			get { return this.location.X + this.size.Width; }
		}

		public int Top
		{
			get { return this.location.Y; }
		}

		public int Bottom
		{
			get { return this.location.Y + this.size.Height; }
		}

		public Size Size
		{
			get { return this.size; }
			set
			{
				if (this.size != value)
				{
					Size oldSize = this.size;
					this.size = value;
					this.Invalidate();

					for (int i = 0; i < this.controls.Count; i++)
					{
						this.controls[i].OnParentSized(ref oldSize);
					}
				}
			}
		}
		
		public int Width
		{
			get { return this.size.Width; }
		}

		public int Height
		{
			get { return this.size.Height; }
		}

		public Rectangle Bounds
		{
			get { return new Rectangle(this.Left, this.Top, this.Width, this.Height); }
		}

		protected Point AbsoluteLocation
		{
			get
			{
				if (this.parent != null)
				{
					return new Point(this.AbsoluteLeft, this.AbsoluteTop);
				}

				return this.location;
			}
		}

		protected int AbsoluteLeft
		{
			get
			{
				if (this.parent != null)
				{
					return this.parent.AbsoluteLeft + this.location.X;
				}

				return this.location.X;
			}
		}

		protected int AbsoluteTop
		{
			get
			{
				if (this.parent != null)
				{
					return this.parent.AbsoluteTop + this.location.Y;
				}

				return this.location.Y;
			}
		}

		protected Rectangle AbsoluteBounds
		{
			get
			{
				Point location = this.AbsoluteLocation;
				return new Rectangle(location.X, location.Y, this.Width, this.Height);
			}
		}

		public Rectangle ClientBounds
		{
			get { return new Rectangle(this.skinMargin.Left, this.skinMargin.Top, this.Width - this.skinMargin.Horizontal, this.Height - this.skinMargin.Vertical); }
		}

		public string Text
		{
			get { return this.text; }
			set
			{
				if (this.text != value)
				{
					this.text = value;
					this.Invalidate();
				}
			}
		}

		public ContentAlignment TextAlign
		{
			get { return this.textAlign; }
			set
			{
				if (this.textAlign != value)
				{
					this.textAlign = value;
					this.Invalidate();
				}
			}
		}

		public virtual bool CanFocus
		{
			get { return this.Enabled && this.Visible; }
		}

		public bool Focused
		{
			get { return this.uiService.ActiveControl == this; }
			set
			{
				if (this.CanFocus && this.Focused != value)
				{
					this.uiService.ActiveControl = value ? this : null;
				}
			}
		}

		public int TabIndex
		{
			get { return this.tabIndex; }
			set	{ this.tabIndex = value; }
		}

		public AnchorStyle Anchor
		{
			get { return this.anchor; }
			set
			{
				if (this.anchor != value)
				{
					this.anchor = value;
					this.Dock = DockStyle.None;
				}
			}
		}

		public DockStyle Dock
		{
			get { return this.dock; }
			set
			{
				if (this.dock != value)
				{
					this.dock = value;
					this.OnDockChanged();
				}
			}
		}

		public bool Contains(Control control)
		{
			while (control != null)
			{
				control = control.Parent;
				if (control == null)
				{
					return false;
				}

				if (control == this)
				{
					return true;
				}
			}

			return false;
		}

		public bool Focus()
		{
			this.Focused = true;
			return this.Focused;
		}

		public bool IsDescendant(Control descendant)
		{
			for (Control control = descendant; control != null; control = control.Parent)
			{
				if (control == this)
				{
					return true;
				}
			}

			return false;
		}
		
		public Point PointToClient(Point point)
		{
			point.X -= this.AbsoluteLeft;
			point.Y -= this.AbsoluteTop;
			return point;
		}

		public Point PointToScreen(Point point)
		{
			point.X += this.AbsoluteLeft;
			point.Y += this.AbsoluteTop;
			return point;
		}

		public Rectangle RectangleToClient(Rectangle rectangle)
		{
			rectangle.Offset(-this.AbsoluteLeft, -this.AbsoluteTop);
			return rectangle;
		}

		public Rectangle RectangleToScreen(Rectangle rectangle)
		{
			rectangle.Offset(this.AbsoluteLeft, this.AbsoluteTop);
			return rectangle;
		}

		public void BringToFront()
		{
			if (this.parent != null)
			{
				// Get the index of this control.
				int index = this.parent.Controls.IndexOf(this);
				if (index != -1)
				{
					// Move the control to the end of the control list.
					this.parent.Controls.RemoveAt(index);
					this.parent.Controls.Insert(this.parent.Controls.Count, this);
				}
			}
		}

		public void SendToBack()
		{
			if (this.parent != null)
			{
				// Get the index of this control.
				int index = this.parent.Controls.IndexOf(this);
				if (index != -1)
				{
					// Move the control to the beginning of the control list.
					this.parent.Controls.RemoveAt(index);
					this.parent.Controls.Insert(0, this);
				}
			}
		}

		#region GameComponent Members

		protected override void Dispose(bool disposing)
		{
			if (disposing)
			{
				// Dispose of the current texture.
				if (this.texture != null)
				{
					this.texture.Dispose();
				}

				// Dispose of the current render target.
				if (this.renderTarget != null)
				{
					this.renderTarget.Dispose();
				}

				// Dispose of all the child controls.
				for (int i = 0; i < this.controls.Count; i++)
				{
					this.controls[i].Dispose();
				}
			}

			// Call inherited method.
			base.Dispose(disposing);
		}

		#endregion

		private void OnParentSized(ref Size oldSize)
		{
			if (this.dock != DockStyle.None)
			{
				this.OnDockChanged();
				return;
			}

			Point location = Point.Zero;
			Size size = Size.Empty;

			if ((this.anchor & AnchorStyle.Right) != AnchorStyle.None)
			{
				if ((this.anchor & AnchorStyle.Left) == AnchorStyle.None)
				{
					location.X = this.Width - oldSize.Width;
				}
				else
				{
					size.Width = this.Width - oldSize.Width;
				}
			}

			if ((this.anchor & AnchorStyle.Bottom) != AnchorStyle.None)
			{
				if ((this.anchor & AnchorStyle.Top) == AnchorStyle.None)
				{
					location.Y = this.Height - oldSize.Height;
				}
				else
				{
					size.Height = this.Height - oldSize.Height;
				}
			}

			if ((this.anchor & AnchorStyle.Left) == AnchorStyle.None && (this.anchor & AnchorStyle.Right) == AnchorStyle.None)
			{
				int width = this.Width - oldSize.Width;
				if ((this.Width % 2) != 0 && width != 0)
				{
					width += width / Math.Abs(width);
				}
				location.X = width >> 1;
			}

			if ((this.anchor & AnchorStyle.Top) == AnchorStyle.None && (this.anchor & AnchorStyle.Bottom) == AnchorStyle.None)
			{
				int height = this.Height - oldSize.Height;
				if ((this.Height % 2) != 0 && height != 0)
				{
					height += height / Math.Abs(height);
				}
				location.Y = height >> 1;
			}

			if (location != Point.Zero)
			{
				this.location.X = this.location.X + location.X;
				this.location.Y = this.location.Y + location.Y;
			}

			if (!size.IsEmpty)
			{
				this.Size += size;
				this.Invalidate();
			}
		}

		private void OnDockChanged()
		{
			if (this.parent == null)
			{
				return;
			}

			Point location = Point.Zero;
			Size size = Size.Empty;

			switch (this.dock)
			{
				case DockStyle.None:
					break;

				case DockStyle.Left:
					location.X = 0 - this.location.X;
					location.Y = 0 - this.location.Y;
					size.Height = this.parent.Height - this.Height;
					break;
					
				case DockStyle.Top:
					location.X = 0 - this.location.X;
					location.Y = 0 - this.location.Y;
					size.Width = this.parent.Width - this.Width;
					break;

				case DockStyle.Right:
					location.X = (this.Right - this.Width) - this.Location.X;
					location.Y = 0 - this.Location.Y;
					size.Height = this.parent.Height - this.Height;
					break;

				case DockStyle.Bottom:
					location.X = 0 - this.Location.X;
					location.Y = (this.Bottom - this.Height) - this.Location.Y;
					size.Width = this.parent.Width - this.Width;
					break;

				case DockStyle.Fill:
					location.X = 0 - this.location.X;
					location.Y = 0 - this.location.Y;
					size = this.parent.Size - this.Size;
					break;
			}

			if (location != Point.Zero)
			{
				this.location.X = this.location.X + location.X;
				this.location.Y = this.location.Y + location.Y;
			}

			if (!size.IsEmpty)
			{
				this.Size += size;
				this.Invalidate();
			}
		}

		private void Invalidate()
		{
			// Invalidate all ancestors.
			if (this.parent != null)
			{
				this.parent.Invalidate();
			}
			
			// Invalidate this control.
			this.invalidate = this.Visible;
		}

		#region DrawableGameComponent Members

		protected override void OnVisibleChanged(object sender, EventArgs args)
		{
			// Call inherited method.
			base.OnVisibleChanged(sender, args);

			// Base invalidation flag on visibility.
			this.invalidate = this.Visible;
		}

		#endregion

		#region IGameComponent Members

		public override void Initialize()
		{
			// Get the ui service.
			this.uiService = this.Game.GetService<IInternalUIService>();
			
			// Call inherited method.
			base.Initialize();

			// Initialize all controls.
			for (int i = 0; i < this.controls.Count; i++)
			{
				this.controls[i].Initialize();
			}
		}

		#endregion

		#region IUpdateable Members

		public override void Update(GameTime gameTime)
		{
			// Call inherited method.
			base.Update(gameTime);

			// Update all controls.
			for (int i = 0; i < this.controls.Count; i++)
			{
				if (this.controls[i].Enabled)
				{
					this.controls[i].Update(gameTime);
				}
			}
		}

		#endregion

		#region IDrawable Members

		public override void Draw(GameTime gameTime)
		{
			// Draw the render target's texture.
			if (this.texture != null)
			{
				Point location = this.AbsoluteLocation;
				this.uiService.SpriteBatch.Draw(this.texture, new Vector2(location.X, location.Y), Color.White);
			}

			// Draw all controls.
			for (int i = 0; i < this.controls.Count; i++)
			{
				if (this.controls[i].Visible)
				{
					this.controls[i].Draw(gameTime);
				}
			}

			// Call inherited method.
			base.Draw(gameTime);
		}

		#endregion

		internal void Prepare(GameTime gameTime)
		{
			if (this.invalidate)
			{
				// Recreate the render target if necessary.
				if (this.renderTarget == null || this.renderTarget.Width != this.GraphicsDevice.PresentationParameters.BackBufferWidth || this.renderTarget.Height != this.GraphicsDevice.PresentationParameters.BackBufferHeight)
				{
					// Dispose of the current texture and render target.
					if (this.texture != null)
					{
						this.texture.Dispose();
					}
					if (this.renderTarget != null)
					{
						this.renderTarget.Dispose();
					}

					// Recreate the render target.
					this.renderTarget = new RenderTarget2D(
						this.GraphicsDevice,
						this.Width,
						this.Height,
						1,
						this.GraphicsDevice.PresentationParameters.BackBufferFormat,
						this.GraphicsDevice.PresentationParameters.MultiSampleType,
						this.GraphicsDevice.PresentationParameters.MultiSampleQuality,
						RenderTargetUsage.PreserveContents);
				}

				// Set the render target.
				this.GraphicsDevice.SetRenderTarget(0, this.renderTarget);
				try
				{
					// Clear the render target to the background color.
					this.GraphicsDevice.Clear(this.backColor);

					// Draw the control.
					this.DrawCore(gameTime);
				}
				finally
				{
					// Reset the back buffer and resolve the render target.
					this.GraphicsDevice.SetRenderTarget(0, null);
					this.texture = this.renderTarget.GetTexture();
				}

				// Prepare all child controls.
				for (int i = 0; i < this.controls.Count; i++)
				{
					this.controls[i].Prepare(gameTime);
				}

				// Reset the invaldiation flag.
				this.invalidate = false;
			}
		}

		protected virtual void DrawCore(GameTime gameTime)
		{
			// Get the skin texture.
			Texture2D texture = this.Game.GetContent().Load<Texture2D>(this.skinAsset);

			// Start drawing.
			this.uiService.SpriteBatch.Begin(SpriteBlendMode.AlphaBlend, SpriteSortMode.Immediate, SaveStateMode.SaveState);

			// Get the destination to render the control.
			Rectangle bounds = new Rectangle(0, 0, this.Width, this.Height);

			// Draw the client area.
			switch (this.clientAreaSkinLayout)
			{
				case ImageLayout.None:
					break;

				case ImageLayout.Center:
					break;

				case ImageLayout.Stretch:
					this.uiService.SpriteBatch.Draw(texture, Control.GetAlignmentRectangle(ref bounds, ref this.skinMargin, ContentAlignment.MiddleCenter), Control.GetAlignmentRectangle(ref this.skinRectangle, ref this.skinMargin, ContentAlignment.MiddleCenter), Color.White, 0.0f, Vector2.Zero, SpriteEffects.None, 0.0f);
					break;

				case ImageLayout.Tile:
					break;

				case ImageLayout.Zoom:
					break;
			}

			// Draw non-client corners.
			this.uiService.SpriteBatch.Draw(texture, Control.GetAlignmentRectangle(ref bounds, ref this.skinMargin, ContentAlignment.TopLeft), Control.GetAlignmentRectangle(ref this.skinRectangle, ref this.skinMargin, ContentAlignment.TopLeft), Color.White, 0.0f, Vector2.Zero, SpriteEffects.None, 0.0f);
			this.uiService.SpriteBatch.Draw(texture, Control.GetAlignmentRectangle(ref bounds, ref this.skinMargin, ContentAlignment.TopRight), Control.GetAlignmentRectangle(ref this.skinRectangle, ref this.skinMargin, ContentAlignment.TopRight), Color.White, 0.0f, Vector2.Zero, SpriteEffects.None, 0.0f);
			this.uiService.SpriteBatch.Draw(texture, Control.GetAlignmentRectangle(ref bounds, ref this.skinMargin, ContentAlignment.BottomLeft), Control.GetAlignmentRectangle(ref this.skinRectangle, ref this.skinMargin, ContentAlignment.BottomLeft), Color.White, 0.0f, Vector2.Zero, SpriteEffects.None, 0.0f);
			this.uiService.SpriteBatch.Draw(texture, Control.GetAlignmentRectangle(ref bounds, ref this.skinMargin, ContentAlignment.BottomRight), Control.GetAlignmentRectangle(ref this.skinRectangle, ref this.skinMargin, ContentAlignment.BottomRight), Color.White, 0.0f, Vector2.Zero, SpriteEffects.None, 0.0f);

			// Draw the non-client lengths.
			switch (this.nonClientAreaSkinLayout)
			{
				case ImageLayout.None:
					break;

				case ImageLayout.Center:
					break;

				case ImageLayout.Stretch:
					this.uiService.SpriteBatch.Draw(texture, Control.GetAlignmentRectangle(ref bounds, ref this.skinMargin, ContentAlignment.TopCenter), Control.GetAlignmentRectangle(ref this.skinRectangle, ref this.skinMargin, ContentAlignment.TopCenter), Color.White, 0.0f, Vector2.Zero, SpriteEffects.None, 0.0f);
					this.uiService.SpriteBatch.Draw(texture, Control.GetAlignmentRectangle(ref bounds, ref this.skinMargin, ContentAlignment.MiddleLeft), Control.GetAlignmentRectangle(ref this.skinRectangle, ref this.skinMargin, ContentAlignment.MiddleLeft), Color.White, 0.0f, Vector2.Zero, SpriteEffects.None, 0.0f);
					this.uiService.SpriteBatch.Draw(texture, Control.GetAlignmentRectangle(ref bounds, ref this.skinMargin, ContentAlignment.MiddleRight), Control.GetAlignmentRectangle(ref this.skinRectangle, ref this.skinMargin, ContentAlignment.MiddleRight), Color.White, 0.0f, Vector2.Zero, SpriteEffects.None, 0.0f);
					this.uiService.SpriteBatch.Draw(texture, Control.GetAlignmentRectangle(ref bounds, ref this.skinMargin, ContentAlignment.BottomCenter), Control.GetAlignmentRectangle(ref this.skinRectangle, ref this.skinMargin, ContentAlignment.BottomCenter), Color.White, 0.0f, Vector2.Zero, SpriteEffects.None, 0.0f);
					break;

				case ImageLayout.Tile:
					// Hold onto current texture address mode.
					TextureAddressMode addressU = this.GraphicsDevice.SamplerStates[0].AddressU;
					TextureAddressMode addressV = this.GraphicsDevice.SamplerStates[0].AddressV;

					// Set the texture address mode to wrap.
					this.GraphicsDevice.SamplerStates[0].AddressU = TextureAddressMode.Wrap;
					this.GraphicsDevice.SamplerStates[0].AddressV = TextureAddressMode.Wrap;
					try
					{
						this.uiService.SpriteBatch.Draw(texture, Control.GetAlignmentRectangle(ref bounds, ref this.skinMargin, ContentAlignment.TopCenter), Control.GetAlignmentRectangle(ref this.skinRectangle, ref this.skinMargin, ContentAlignment.TopCenter), Color.White, 0.0f, Vector2.Zero, SpriteEffects.None, 0.0f);
						this.uiService.SpriteBatch.Draw(texture, Control.GetAlignmentRectangle(ref bounds, ref this.skinMargin, ContentAlignment.MiddleLeft), Control.GetAlignmentRectangle(ref this.skinRectangle, ref this.skinMargin, ContentAlignment.MiddleLeft), Color.White, 0.0f, Vector2.Zero, SpriteEffects.None, 0.0f);
						this.uiService.SpriteBatch.Draw(texture, Control.GetAlignmentRectangle(ref bounds, ref this.skinMargin, ContentAlignment.MiddleRight), Control.GetAlignmentRectangle(ref this.skinRectangle, ref this.skinMargin, ContentAlignment.MiddleRight), Color.White, 0.0f, Vector2.Zero, SpriteEffects.None, 0.0f);
						this.uiService.SpriteBatch.Draw(texture, Control.GetAlignmentRectangle(ref bounds, ref this.skinMargin, ContentAlignment.BottomCenter), Control.GetAlignmentRectangle(ref this.skinRectangle, ref this.skinMargin, ContentAlignment.BottomCenter), Color.White, 0.0f, Vector2.Zero, SpriteEffects.None, 0.0f);
					}
					finally
					{
						// Reset texture address mode.
						this.GraphicsDevice.SamplerStates[0].AddressU = addressU;
						this.GraphicsDevice.SamplerStates[0].AddressV = addressV;
					}

					break;

				case ImageLayout.Zoom:
					break;
			}

			// Draw the background image.
			if (!string.IsNullOrEmpty(this.backgroundImageAsset))
			{
				Texture2D backgroundTexture = this.Game.GetContent().Load<Texture2D>(this.backgroundImageAsset);

				// Draw the client area.
				switch (this.backgroundImageLayout)
				{
					case ImageLayout.None:
						break;

					case ImageLayout.Center:
						break;

					case ImageLayout.Stretch:
						this.uiService.SpriteBatch.Draw(backgroundTexture, Control.GetAlignmentRectangle(ref bounds, ref this.skinMargin, ContentAlignment.MiddleCenter), Control.GetAlignmentRectangle(ref this.skinRectangle, ref this.skinMargin, ContentAlignment.MiddleCenter), Color.White, 0.0f, Vector2.Zero, SpriteEffects.None, 0.0f);
						break;

					case ImageLayout.Tile:
						break;

					case ImageLayout.Zoom:
						break;
				}
			}

			// Draw text.
			if (!String.IsNullOrEmpty(this.text))
			{
				SpriteFont font = this.Game.GetContent().Load<SpriteFont>(this.fontAsset);			
				SpriteFontExtension.DrawText(
					this.uiService.SpriteBatch,
					this.text,
					font,
					this.ClientBounds,
					this.fontColor,
					Control.ConvertTo(this.textAlign));
			}
			
			// Done drawing.
			this.uiService.SpriteBatch.End();
		}

		private static TextFormatFlags ConvertTo(ContentAlignment alignment)
		{
			TextFormatFlags flags = TextFormatFlags.WordBreak;
			switch (alignment)
			{
				case ContentAlignment.TopLeft:
					break;

				case ContentAlignment.TopCenter:
					flags |= TextFormatFlags.HorizontalCenter;
					break;

				case ContentAlignment.TopRight:
					flags |= TextFormatFlags.Right;
					break;

				case ContentAlignment.MiddleLeft:
					flags |= TextFormatFlags.VerticalCenter;
					break;

				case ContentAlignment.MiddleCenter:
					flags |= TextFormatFlags.HorizontalCenter | TextFormatFlags.VerticalCenter;
					break;

				case ContentAlignment.MiddleRight:
					flags |= TextFormatFlags.Right | TextFormatFlags.VerticalCenter;
					break;

				case ContentAlignment.BottomLeft:
					flags |= TextFormatFlags.Bottom;
					break;

				case ContentAlignment.BottomCenter:
					flags |= TextFormatFlags.Bottom | TextFormatFlags.HorizontalCenter;
					break;

				case ContentAlignment.BottomRight:
					flags |= TextFormatFlags.Right | TextFormatFlags.Bottom;
					break;
			}

			return flags;
		}

		private static Rectangle GetAlignmentRectangle(ref Rectangle rectangle, ref Padding margin, ContentAlignment alignment)
		{
			// Base alignment rectangle on the alignment parameter.
			switch (alignment)
			{
				case ContentAlignment.TopLeft:
					return new Rectangle(
						rectangle.Left,
						rectangle.Top,
						margin.Left,
						margin.Top);

				case ContentAlignment.TopCenter:
					return new Rectangle(
						rectangle.Left + margin.Left,
						rectangle.Top,
						rectangle.Width - margin.Horizontal,
						margin.Top);

				case ContentAlignment.TopRight:
					return new Rectangle(
						rectangle.Right - margin.Right,
						rectangle.Top,
						margin.Right,
						margin.Top);

				case ContentAlignment.MiddleLeft:
					return new Rectangle(
						rectangle.Left,
						rectangle.Top + margin.Top,
						margin.Left,
						rectangle.Height - margin.Vertical);

				case ContentAlignment.MiddleCenter:
					return new Rectangle(
						rectangle.Left + margin.Left,
						rectangle.Top + margin.Top,
						rectangle.Width - margin.Horizontal,
						rectangle.Height - margin.Vertical);

				case ContentAlignment.MiddleRight:
					return new Rectangle(
						rectangle.Right - margin.Right,
						rectangle.Top + margin.Top,
						margin.Right,
						rectangle.Height - margin.Vertical);

				case ContentAlignment.BottomLeft:
					return new Rectangle(
						rectangle.Left,
						rectangle.Bottom - margin.Bottom,
						margin.Left,
						margin.Bottom);

				case ContentAlignment.BottomCenter:
					return new Rectangle(
						rectangle.Left + margin.Left,
						rectangle.Bottom - margin.Bottom,
						rectangle.Width - margin.Horizontal,
						margin.Bottom);

				case ContentAlignment.BottomRight:
					return new Rectangle(
						rectangle.Right - margin.Right,
						rectangle.Bottom - margin.Bottom,
						margin.Right,
						margin.Bottom);
			}

			// Return an empty rectangle.  Should never get here.
			return Rectangle.Empty;
		}
	}
}